package scijava.stats;

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

import scijava.util.NumberUtil;

public class BasicStats {
	
	public static double meanOfIntegers(List<Integer> vals){
		return BasicStats.meanOfDoubles(NumberUtil.convertIntegersToDoubles(vals));
	}

	/**
	 * Method that computes the mean of a list of integers.
	 * 
	 * @param vals
	 *            - a non-empty list of integers
	 * @return - the mean of the values in a double
	 */
	public static double meanOfDoubles(Collection<Double> vals) {
		/*
		 * div zero errors are bad...
		 */
		if (vals.size() == 0) {
			throw new RuntimeException("Asked to compute the mean of an empty list!");
		}

		double sum = 0;
		for (double tVal : vals) {
			sum += tVal;
		}
		return sum / ((double) vals.size());
	}
	
	public static double medianOfIntegers(Collection<Integer> vals){
		return BasicStats.medianOfDoubles(NumberUtil.convertIntegersToDoubles(vals));
	}

	/**
	 * Method that computes the median of a list of integers.
	 * 
	 * @param vals
	 *            - a non-empty list of ints
	 * @return the median of the supplied list
	 */
	public static double medianOfDoubles(Collection<Double> vals) {
		/*
		 * median on empty lists, that a nono..
		 */
		if (vals.size() == 0) {
			throw new RuntimeException("Asked to compute the median of an empty list!");
		}

		/*
		 * create a clone of the list, since sorting of the original list would
		 * be a side effect of this method and we want to avoid that.
		 */
		List<Double> sortedList = new ArrayList<Double>();
		for (double tVal : vals) {
			sortedList.add(tVal);
		}

		/*
		 * Actually compute the median
		 */
		Collections.sort(sortedList);
		if (sortedList.size() % 2 == 0) {
			double a = sortedList.get(sortedList.size() / 2);
			double b = sortedList.get((sortedList.size() / 2) - 1);
			return (a + b) / 2.0;
		} else {
			int pos = sortedList.size() / 2;
			return sortedList.get(pos);
		}
	}
	
	public static double stdDevOfIntegers(Collection<Integer> vals){
		return BasicStats.stdDevOfDoubles(NumberUtil.convertIntegersToDoubles(vals));
	}

	/**
	 * Method that computes the standard deviation of a list of integer.s
	 * 
	 * @param vals
	 *            - a non-empty list of ints to compute over
	 * @return - the std deviation of the supplied list
	 */
	public static double stdDevOfDoubles(Collection<Double> vals) {
		/*
		 * div zero errors are bad...
		 */
		if (vals.size() == 0) {
			throw new RuntimeException("Asked to compute the std dev of an empty list!");
		}

		double mean = BasicStats.meanOfDoubles(vals);

		double sum = 0;
		for (double tVal : vals) {
			sum += Math.pow((tVal - mean), 2);
		}

		return Math.sqrt(sum / ((double) vals.size()));
	}
	

}
